package com.seguriapp.crimeactivity.gwt.server;

import java.util.ArrayList;
import java.util.List;

import net.customware.gwt.dispatch.server.ExecutionContext;
import net.customware.gwt.dispatch.shared.DispatchException;
import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.restlet.data.MediaType;
import org.restlet.resource.ClientResource;

import com.seguriapp.common.config.GlobalConfigLoader;
import com.seguriapp.common.gwt.server.AbstractSeguriAppHandler;
import com.seguriapp.crimeactivity.gwt.shared.GetCrimeActivityDataAction;
import com.seguriapp.crimeactivity.gwt.shared.GetCrimeActivityDataResult;
import com.seguriapp.entities.Complaint;
import com.seguriapp.entities.CrimeCategory;

public class GetCrimeActivityDataHandler extends AbstractSeguriAppHandler<GetCrimeActivityDataAction, GetCrimeActivityDataResult> {

  private static final Logger LOGGER = Logger.getLogger(GetCrimeActivityDataHandler.class);

  public Class<GetCrimeActivityDataAction> getActionType() {
    return GetCrimeActivityDataAction.class;
  }

  public GetCrimeActivityDataResult execute(final GetCrimeActivityDataAction action, final ExecutionContext context) throws DispatchException {
    final GetCrimeActivityDataResult result = new GetCrimeActivityDataResult();
    try {
      final String url = GlobalConfigLoader.getInstance().getGlobalConfig().getBackEndUrl()
          .concat(GlobalConfigLoader.getInstance().getGlobalConfig().getGetCriminalActivityMap());
      final ClientResource resource = new ClientResource(url);
      final String mapInfoJs = resource.post(
          convertDataToJsonString(action.getOptions(), action.getZoomLevel(), GlobalConfigLoader.getInstance().getGlobalConfig().getDeviceId()),
          MediaType.TEXT_PLAIN).getText();
      LOGGER.info("Data received : \n" + mapInfoJs);
      result.setCriminalItemsList(getJsonDataFromString(mapInfoJs));
      result.setDefaultLatitude(GlobalConfigLoader.getInstance().getGlobalConfig().getDefaultLatitude());
      result.setDefaultLongitude(GlobalConfigLoader.getInstance().getGlobalConfig().getDefaultLongitude());
    } catch (Exception e) {
      LOGGER.error(e.getStackTrace());
      e.printStackTrace();
    }
    return result;
  }

  private String convertDataToJsonString(final String mapOptions, final int zoomLevel, final int deviceId) {
    if (mapOptions == null) {
      return StringUtils.EMPTY;
    }
    final JSONObject obj = new JSONObject();
    try {
      obj.put("mapOptions", mapOptions);
      obj.put("zoomLevel", zoomLevel);
      obj.put("deviceType", deviceId);
      obj.put("allResults", 1);
    } catch (JSONException e) {
      LOGGER.error(e.getStackTrace());
    }
    LOGGER.info("Sending Data : \n" + obj.toString());
    return obj.toString();
  }

  private List<Complaint> getJsonDataFromString(final String mapInfoJs) {
    final List<Complaint> criminalItemsList = new ArrayList<Complaint>();
    final JSONObject root = JSONObject.fromObject(mapInfoJs);
    JSONArray dataArray = null;
    JSONObject jo = null;
    if (root.has("complaints")) {
      dataArray = root.getJSONArray("complaints");
      if (dataArray != null) {
        for (int i = 0; i < dataArray.size(); i++) {
          jo = dataArray.getJSONObject(i);
          final Complaint complaint = processjSONObject(jo);
          if (complaint != null) {
            criminalItemsList.add(complaint);
          }
        }
      }
    }
    return criminalItemsList;
  }

  private Complaint processjSONObject(final JSONObject jo) {
    if (jo.has("crimelatitude") && jo.has("crimelongitude") && jo.has("address") && jo.has("address")) {
      final Complaint complaint = new Complaint();
      complaint.setCrimeLatitude(jo.getDouble("crimelatitude"));
      complaint.setCrimeLongitude(jo.getDouble("crimelongitude"));
      complaint.setAddress(jo.getString("address"));
      final CrimeCategory crimeCategory = new CrimeCategory();
      final JSONObject crimeCategoryJson = jo.getJSONObject("category");
      crimeCategory.setId(crimeCategoryJson.getLong("id"));
      crimeCategory.setName(crimeCategoryJson.getString("name"));
      crimeCategory.setDescription(crimeCategoryJson.getString("description"));
      complaint.setCategory(crimeCategory);
      return complaint;
    }
    return null;
  }

}
